﻿using CKS.Core.Framework;
using CKS.PLC.Core.Siemens;
using Mapster;
using S7.Net;
using S7.Net.Types;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core
{
    public class SieminDecoder
    {

        
        /// <summary>
        /// 相同DB块内的全部解析数据
        /// </summary>
        public List<DecodeValue> Values { get; set; }


        public SieminDecoder(List<CksPlcDataPosition> points)
        {
            Points = points;
            Values = new List<DecodeValue>();
            foreach (var point in points) {
                if (point.ParseType.ToLower().Equals("struct"))
                    continue;
                DecodeValue dv = new DecodeValue();
                if (point.ParseType.StartsWith("string"))  //构造时初始化默认值，避免首次运行异常触发
                    dv.Value = dv.OldValue = "";
                else
                    dv.Value = dv.OldValue = (int)0;
               
                dv.Position = point;
               
                Values.Add(dv);
            }
        }

        public List<CksPlcDataPosition> Points { get; }

        public List<DecodeValue> Decode(byte[] blockBytes)
        {
            foreach (var val in Values) {
                var point = val.Position;
                val.Position = point;

                var res = SieminDecoder.SimpleDecode(blockBytes, point.BytePosition, point.ByteLength, point.ParseType);
                val.Value = res.Value;
                val.DecodeObject = res;
            }
            return Values;
        }


        public static DecodeObject SimpleDecode(byte[] bytes, decimal position, int count,string ParseType)
        {
            DecodeObject obj = new DecodeObject();
            int startIndex = (int)position;
            int bitindex = (int)(position * 10) % 10;
            //ArraySegment<byte> bytes = new ArraySegment<byte>(blockBytes);
            //var buffer = bytes.Slice(startIndex, count).Reverse().ToArray(); //大小端问题，需要反转字节数组
            var lowerType = ParseType.ToLower();
            if (lowerType.IsArrayType(out int arraylenth, out string type2))
            {
                //数组暂时只处理 int
                if (type2.IsS7Int16())
                {
                    List<short> shorts = new List<short>();

                    try
                    {
                        for (int i = 0; i < arraylenth; i++)
                        {
                            var val = DataConversion.GetInt16DataByBytes(bytes, startIndex);
                            startIndex += 2;  // int16偏移是2字节
                            shorts.Add(val);
                        }
                        obj.Value = shorts;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if (type2.Equals("word"))
                {
                    try
                    {
                        List<ushort> shorts = new List<ushort>();
                        for (int i = 0; i < arraylenth; i++)
                        {
                            var val = DataConversion.GetWordDataByBytes(bytes, startIndex);
                            startIndex += 2;  // int16偏移是2字节
                            shorts.Add(val);
                        }
                        obj.Value = shorts;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if (type2.Equals("byte"))
                {
                    try
                    {
                        List<byte> shorts = new List<byte>();
                        for (int i = 0; i < arraylenth; i++)
                        {
                            var val = bytes.Skip(startIndex).Take(1).First();
                            startIndex += 1;  // 偏移字节数
                            shorts.Add(val);
                        }
                        obj.Value = shorts;
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
                else if (type2.Equals("char"))
                {
                    try
                    {
                        List<char> shorts = new List<char>();
                        for (int i = 0; i < arraylenth; i++)
                        {
                            var val = DataConversion.GetChar(bytes, startIndex);
                            startIndex += 1;  // 
                            shorts.Add((char)val);
                        }
                        obj.Value = shorts;
                        obj.IsCharArray = true;
                        var charArray = shorts.ToArray();
                        int nullIndex = Array.IndexOf(charArray, '\0');

                        string CharString = nullIndex >= 0
                            ? new string(charArray, 0, nullIndex)  // 截取到\0之前的部分
                            : new string(charArray);  // 没有\0，使用整个数组
                        obj.CharString = CharString;
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
                else if(type2.IsS7Real())
                {
                    List<decimal> decimals = new List<decimal>();
                    try
                    {
                        for (int i = 0; i < arraylenth; i++)
                        {

                            var val = DataConversion.GetFloatDataByBytes(bytes, startIndex);
                            startIndex += 4;  // real偏移是4字节
                            decimals.Add((decimal)val);
                        }
                        obj.Value = decimals;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if (type2.Equals("bool"))
                {
                    List<bool> decimals = new List<bool>();
                    try
                    {

                        for (int i = 0; i < arraylenth; i++)
                        {
                            //bool 需要根据位算出是第几个byte
                            var byteindex = i / 8; // bit 所在的byte位置
                            var boolRealByteIndex = startIndex + byteindex;
                            var bit = i % 8;
                            var val = DataConversion.GetBit(bytes[boolRealByteIndex], bit);

                            decimals.Add(val);
                        }
                        obj.Value = decimals;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }
                else if(type2.IsS7String())
                {
                    List<string> strings = new List<string>();
                    try
                    {
                        for (int i = 0; i < arraylenth; i++)
                        {
                            int length = 0;
                            if (type2.Contains("string"))
                            {
                                length = Regex.Match(type2, "[0-9]+").Value.ToInt() + 2;
                            }

                            var val = DataConversion.GetStringDataByBytes(bytes, startIndex, length);
                            startIndex += length;  // real偏移是4字节
                            strings.Add(val);
                        }
                        obj.Value = strings;
                    }
                    catch (Exception ex)
                    {

                        throw;
                    }
                }

                if (obj.Value == null)
                    obj.Value = string.Empty; //数组占位暂时不解析
                return obj; 
            }

            obj.Value = ParseType.ToLower() switch
            {
                "char" => DataConversion.GetChar(bytes, startIndex),
                "string" => DataConversion.GetStringDataByBytes(bytes, startIndex, count),
                "int16" => DataConversion.GetInt16DataByBytes(bytes, startIndex),
                "word" => DataConversion.GetWordDataByBytes(bytes, startIndex),
                "int32" => DataConversion.GetInt32DataByBytes(bytes, startIndex),
                "double" => DataConversion.GetDoubleDataByBytes(bytes, startIndex),
                "float" => DataConversion.GetFloatDataByBytes(bytes, startIndex),
                "bool" => DataConversion.GetBit(bytes[startIndex], bitindex),
                "array" => string.Empty,
                "dtl" => DataConversion.GetDTL(bytes, startIndex),
                "dt" => DataConversion.GetDT(bytes, startIndex),
                _ => throw new NotImplementedException("未实现该数据类型的解析")
            };

            return obj;
        }

        public static bool IsArrayType(string ArrayType, out int arrayLenth, out string ParseType)
        {
            ParseType = "";
            arrayLenth = 0;
            var dataType = ArrayType.ToLower();
            if (dataType.StartsWith("array[") && dataType.Contains("of"))
            {
                //Array[0..63] of Word

                var matches = Regex.Matches(dataType, "[0-9]+");
                if (matches.Count == 2)
                {
                    var Start = matches[0].Value.ObjToInt();
                    var End = matches[1].Value.ObjToInt();
                    double sizelenth = End - Start + 1; //数组Length
                    arrayLenth = (int)sizelenth;
                    var arrayType = dataType.Split(' ')[2];
                    ////计算字节Length
                    sizelenth = arrayType switch
                    {
                        "bool" => GetBoolLenth(sizelenth),
                        "int" => sizelenth * 2,
                        "word" => sizelenth * 2,
                        "dword" => sizelenth * 4, //uint
                        "dint" => sizelenth * 4,
                        "real" => sizelenth * 4,
                        "lreal" => sizelenth * 8,
                        _ => sizelenth
                    };
                    ParseType = arrayType;
                    //

                    //
                    return true;
                }
                else if (matches.Count == 3 && dataType.Contains("of string"))
                {
                    var arrayType = dataType.Split(' ')[2];
                    ParseType = arrayType;
                    var Start = matches[0].Value.ObjToInt();
                    var End = matches[1].Value.ObjToInt();
                    decimal sizelenth = End - Start + 1;
                    arrayLenth = (int)sizelenth;

                    return true;
                }

            }
            return false;
        }
        private static double GetBoolLenth(double sizelenth)
        {
            int d = (int)(sizelenth / 8);
            var yu = sizelenth % 8;
            if (yu == 0)
                return d;
            return (double)d + (yu / 10);
        }
    }

    /// <summary>
    /// 解析数据类型
    /// </summary>
    public class DecodeValue 
    {
        /// <summary>
        /// 当前数据的点位
        /// </summary>
        public CksPlcDataPosition Position { get; set; }
        /// <summary>
        /// 读取值
        /// </summary>
        public object Value { get; set; }

        public DecodeObject DecodeObject { get; set; }
        /// <summary>
        /// 读取旧值
        /// </summary>
        public object OldValue { get; set; }

        private bool _isFirstGetChange = true;
        public bool IsChange
        {
            get
            {
                if (_isFirstGetChange)
                {
                    _isFirstGetChange = false;
                    return true;
                }

                //判断是否数组
                if(this.Position.ParseType.IsArrayType(out int len, out string type2))
                {
                    if(Value is Array || Value is System.Collections.IList)
                    {
                        try
                        {
                            var arr1 = Value.Adapt<List<string>>();
                            var arr2 = OldValue.Adapt<List<string>>();
                            for (int i = 0; i < arr1.Count; i++)
                            {
                                var a = arr1[i];
                                var b = arr2[i];
                                if (a != b)
                                    return true;
                            }
                            return false;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                }
         
                return !(Value.ToString().Equals(OldValue.ToString()));
            }
        }

        public ISiemensClient SiemensClient { get; set; }
        /// <summary>
        /// 该点位关联的步骤需要操作的数据位置
        /// </summary>
        public List<CksPlcDataPosition> LinkPositions { get; set; }
        /// <summary>
        /// 该订阅点关联数据块的全部点位
        /// 当前点位数据关联的数据源；批量读取数据块的缓存；
        /// </summary>
        public List<DecodeValue> AllValues { get; set; }
        public List<CksPlcDataPosition> AllPositions { get; set; }

        public object GetLinkData(int DataId)
        {
            try
            {

                var one = AllValues.Find(a => a.Position.LinkActionId == Position.ActionId && a.Position.DataId == DataId);
                return one.Value;
            }
            catch (Exception)
            {
                return null;
            }
        }
        public object GetLinkData(int ActionId, int DataId)
        {
            try
            {

                var one = AllValues.Find(a => a.Position.LinkActionId == ActionId && a.Position.DataId == DataId);
                return one.Value;
            }
            catch (Exception)
            {
                return null;
            }
        }



        public CksPlcDataPosition GetPosition(int db, int action, int dataid = 0)
        {
            return AllPositions.Find(a => a.BlockDb == db && a.ActionId == action && a.DataId == dataid);
        }

        public CksPlcDataPosition GetReplyPosition(int db, int action,string actionKey = "", int dataid = 0)
        {
            return AllPositions.Find(a => a.EffectType == 0 && a.BlockDb == db && a.ActionId == action&& a.ActionKey == actionKey && a.DataId == dataid);
        }

        public List<DecodeValue> GetActionAllData()
        {
            try
            {

                return AllValues.FindAll(a => a.Position.LinkActionId == Position.ActionId);
                 
            }
            catch (Exception)
            {
                return null;
            }
        }

        public object GetLocationData(int location, int DataId)
        {
            try
            {

                var one = AllValues.Find(a => a.Position.LinkActionId == Position.ActionId
                            && (a.Position.LocationId == location || a.Position.LocationId == 0)
                            && a.Position.DataId == DataId);
                return one.Value;
            }
            catch (Exception)
            {
                return null;
            }
        }
        /// <summary>
        /// 获取关联的动作编号的数据
        /// </summary>
        /// <param name="location"></param>
        /// <param name="DataId"></param>
        /// <returns></returns>
        public DecodeObject GetLinkDecodeData(int location, int DataId)
        {
            try
            {

                var one = AllValues.Find(a => a.Position.LinkActionId == Position.ActionId
                            && (a.Position.LocationId == location || a.Position.LocationId == 0)
                            && a.Position.DataId == DataId);
                return one.DecodeObject;
            }
            catch (Exception)
            {
                return null;
            }
        }


        /// <summary>
        /// 获取当前动作数据的最大分组/位置
        /// </summary>
        /// <returns></returns>
        public int GetMaxLocation()
        {
            var maxLocation = AllPositions.FindAll(a => a.BlockDb == Position.BlockDb && a.LinkActionId == Position.ActionId)
                 .Max(a => a.LocationId);
            return maxLocation;
        }
    }

    public class DecodeObject
    {
        public object Value { get; set; }

        public bool IsCharArray { get; set; }

        public string CharString { get; set; }

    }
}
